//本包包含了配对方法的生成
package Model.TransFormModel;

import Model.SurroundModel.Ship;

import java.util.ArrayList;

public class TMat {
    private int number = 0;//船的数量
    private Ship[] oldShip;//变换之前各个船的坐标
    private Ship[] newShip;//变换之后各个船的坐标
    private double[][] P;//预处理计算变换前后每个坐标变换对应的概率
    public Ship[][] SE;//用二维数组进行船的配对，[][0]表示变换前船的坐标，[][1]表示变换后船的坐标

    public TMat(Ship[][] se) {
        SE = se;
    }

    public TMat(int number, ArrayList<Ship> p, ArrayList<Ship> q) {
        this.number = number;
        oldShip = p.toArray(new Ship[number + 1]);
        newShip = q.toArray(new Ship[number + 1]);
        P = new double[number + 1][number + 1];
        SE = new Ship[number + 1][2];
    }

    //f函数，计算欧氏距离
    public double f(Ship p, Ship q) {
        return Math.sqrt(Math.pow((p.x - q.x), 2) + Math.pow((p.y - q.y), 2));
    }

    //计算e的n次指数
    public double pow(double n) {
        return Math.pow(Math.E, n);
    }

    //计算任意新旧两船配对的概率
    public double P(Ship p, Ship q) {
        double sum = 0;
        for (int i = 1; i < P.length; i++) {
            sum += pow(-f(p, newShip[i - 1]));//计算P概率的分母
        }
        return (pow(-f(p, q))) / sum;//返回指定p,q两船配对的概率
    }

    //判断元素是否在数组内
    public static boolean useList(ArrayList arr, int targetValue) {
        return arr.contains(targetValue);
    }

    //进行预处理，计算所有Pij的值
    public void pretreat() {
        double sum = 0;
        for (int i = 1; i < P.length; i++) {
            for (int k = 1; k < P.length; k++) {
                sum += pow(-f(oldShip[i - 1], newShip[k - 1]));//计算P概率的分母
            }
            for (int j = i; j < P.length; j++) {
                P[i][j] = (pow(-f(oldShip[i - 1], newShip[j - 1]))) / sum;//计算Pij的值
            }
            sum = 0;
        }
    }

    //贪心筛选
    public void screen() {
        double p = -1;
        ArrayList<Integer> abandon = new ArrayList<Integer>();//用于存储丢弃的E-Set集合值
        for (int i = 1; i < P.length; i++) {
            for (int j = 1; j < P.length; j++) {
                if (useList(abandon, j))
                    continue;
                if (P[i][j] > p) {
                    p = P[i][j];
                    if (abandon.size() < i)
                        abandon.add(j);
                    else
                        abandon.set(i - 1, j);
                }
            }
            p = -1;
            SE[i][0] = oldShip[i - 1];
            SE[i][1] = newShip[abandon.get(i - 1) - 1];
        }
    }

    //配队修正：交叉修正（这里K值可以根据实际情况修改）
    //参数为设置交叉修正的次数，可根据实际情况修改
    public void CRcorrect(double K) {
        double P1 = 0;//原先配队的概率
        double P2 = 0;//交叉修正后配队的概率
        Ship temp = null;//用于交换的临时变量

        //从第一次配队开始每相邻两次配队进行交叉修正
        for (int i = 1; i <= K; i++) {
            P1 = P(SE[i][0], SE[i][1]) * P(SE[i + 1][0], SE[i + 1][1]);
            P2 = P(SE[i][0], SE[i + 1][1]) * P(SE[i + 1][0], SE[i][1]);
            //如果交叉后概率增大则交换位置
            if (P2 > P1) {
                temp = SE[i][1];
                SE[i][1] = SE[i + 1][1];
                SE[i + 1][1] = temp;
            }
        }
    }

    //相对位置修正（这里K值可以根据实际情况修改）
    public void RPcorrect(double K) {
        double x1 = 0;//初始队列两船横坐标之差
        double x2 = 0;//变换后队列两船横坐标之差
        double y1 = 0;//初始队列两船纵坐标之差
        double y2 = 0;//变换后队列两船纵坐标之差
        Ship temp = null;//用于交换的临时变量

        //从第一次配队开始每相邻两次配队进行相对位置修正
        for (int i = 1; i <= K; i++) {
            for (int j = i + 1; j < K; j++) {
                x1 = SE[i][0].x - SE[j][0].x;
                y1 = SE[i][0].y - SE[j][0].y;
                x2 = SE[i][1].x - SE[j][1].x;
                y2 = SE[i][1].y - SE[j][1].y;
                //如果判断两路径交叉则交换位置
                if (x1 * x2 <= 0 && y1 * y2 <= 0) {
                    temp = SE[i][1];
                    SE[i][1] = SE[j][1];
                    SE[j][1] = temp;
                }
            }
        }
        for (int i = (int) K - 1; i > 1; i--) {
            for (int j = i - 1; j >= 1; j--) {
                x1 = SE[i][0].x - SE[j][0].x;
                y1 = SE[i][0].y - SE[j][0].y;
                x2 = SE[i][1].x - SE[j][1].x;
                y2 = SE[i][1].y - SE[j][1].y;
                //如果判断两路径交叉则交换位置
                if (x1 * x2 <= 0 && y1 * y2 <= 0) {
                    temp = SE[i][1];
                    SE[i][1] = SE[j][1];
                    SE[j][1] = temp;
                }
            }
        }
    }

}
